function shantenLessThan(hand, s) {
	return _isHu(hand, s)
}
function shanten(hand) {
	for (let joker = 0; ; ++joker) {
		if (joker > 13 || shantenLessThan(hand, joker + 1)) {
			return joker
		}
	}
}
function hu(hand, tsumo) {
	if (_isHu(hand)) {
		return {
			tsumo: tsumo,
			points: 1
		}
	} else {
		return undefined
	}
}
function tenpai(hand) {
	if (_isHu(hand, 1)) {
		return {
			points: 1
		}
	} else {
		return undefined
	}
}
function checkAddedMelds(tiles, currentMelds) {
	let melds = []

	// Check added kongs
	for (const meld of currentMelds) if (meld[0] === CHOICE_PUNG) {
		const value = meld[1] - 40
		for (const set of searchSetFromArray(tiles, [
			tile => getTileValue(tile) === value,
		])) {
			melds.push([CHOICE_ADDED_KONG, value + 40, 0, set])
		}
	}
	return melds
}
function checkConcealedMelds(tiles) {
	let melds = []

	// Check kongs
	for (const value of sortAndUnique(tiles.map(getTileValue))) {
		for (const set of searchSetFromArray(tiles, [
			tile => getTileValue(tile) === value,
			tile => getTileValue(tile) === value,
			tile => getTileValue(tile) === value,
			tile => getTileValue(tile) === value,
		])) {
			melds.push([CHOICE_CONCEALED_KONG, value + 40, 0, set])
		}
	}
	return melds
}
function checkMelds(tiles, discarded) {
	const d = getTileValue(discarded)
	let melds = []

	// Check chows
	if ((d & 3) !== 3) {
		// 12[3]
		if (d >= 12) {
			for (const set of searchSetFromArray(tiles, [
				tile => getTileValue(tile) === d - 8,
				tile => getTileValue(tile) === d - 4,
			])) {
				melds.push([CHOICE_CHOW, d + 72, discarded, set])
			}
		}
		// 1[2]3
		if (d >= 8 && d < 36) {
			for (const set of searchSetFromArray(tiles, [
				tile => getTileValue(tile) === d - 4,
				tile => getTileValue(tile) === d + 4,
			])) {
				melds.push([CHOICE_CHOW, d + 76, discarded, set])
			}
		}
		// [1]23
		if (d < 32) {
			for (const set of searchSetFromArray(tiles, [
				tile => getTileValue(tile) === d + 4,
				tile => getTileValue(tile) === d + 8,
			])) {
				melds.push([CHOICE_CHOW, d + 80, discarded, set])
			}
		}
	}

	// Check pungs
	for (const set of searchSetFromArray(tiles, [
		tile => getTileValue(tile) === d,
		tile => getTileValue(tile) === d,
	])) {
		melds.push([CHOICE_PUNG, d + 40, discarded, set])
	}

	// Check kongs
	for (const set of searchSetFromArray(tiles, [
		tile => getTileValue(tile) === d,
		tile => getTileValue(tile) === d,
		tile => getTileValue(tile) === d,
	])) {
		melds.push([CHOICE_KONG, d + 40, discarded, set])
	}
	return melds
}